package cn.sc.summer.gateway.config;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.sc.summer.constant.gateway.GatewayConstant;
import cn.sc.summer.constant.util.ConvertUtil;
import cn.sc.summer.gateway.properties.GatewayRouteConfigProperties;
import cn.sc.summer.gateway.service.RouteService;
import cn.sc.summer.redis.util.RedisHelper;
import cn.sc.summer.redis.util.RouteUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;

/**
 * 类名：动态路由实现类
 *
 * @author a-xin
 * @date 2023/12/7 16:25
 */
@Slf4j
@Component
@RefreshScope
public class GatewayRouteInitConfig {

    @Resource
    private GatewayRouteConfigProperties configProperties;

    @Resource
    private NacosConfigProperties nacosConfigProperties;

    @Resource
    private RouteService routeService;

    /**
     * nacos 配置服务
     */
    @Resource
    private ConfigService configService;

    /**
     * JSON 转换对象
     */
    private final ObjectMapper objectMapper = new ObjectMapper();

    @PostConstruct
    public void init() {
        log.info("==> Starts gateway dynamic route initialization...");
        RedisHelper.del(GatewayConstant.SWAGGER_DYNAMIC_ROUTING);
        try {
            // getConfigAndSignListener()方法 发起长轮询和对dataId数据变更注册监听的操作
            // getConfig 只是发送普通的HTTP请求
            String initConfigInfo = configService.getConfigAndSignListener(configProperties.getDataId(),
                    configProperties.getGroup(),
                    nacosConfigProperties.getTimeout(),
                    new Listener() {
                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String configInfo) {
                    if (StrUtil.isNotBlank(configInfo)) {
                        log.info("==> Received the gateway routing update configuration");
                        List<RouteDefinition> routeDefinitions = ConvertUtil.toObject(configInfo, new TypeReference<List<RouteDefinition>>() {
                        });

                        Map<String, String> definitionMap = RouteUtil.getRouteMap();
                        for (RouteDefinition definition : Objects.requireNonNull(routeDefinitions)) {
                            routeService.update(definition);
                            definitionMap.remove(definition.getId());
                        }
                        if (CollUtil.isNotEmpty(definitionMap)) {
                            definitionMap.forEach((key, value) -> routeService.del(JSONObject.parseObject(value, RouteDefinition.class)));
                        }
                    } else {
                        log.warn("Currently gateway does not have dynamic routing configurations");
                    }
                }
            });

            log.info("==> Obtain the current dynamic route configuration of the gateway");
            if (StrUtil.isNotBlank(initConfigInfo)) {
                List<RouteDefinition> routeDefinitions = objectMapper.readValue(initConfigInfo, new TypeReference<List<RouteDefinition>>() {
                });
                for (RouteDefinition definition : routeDefinitions) {
                    routeService.add(definition);
                }
            } else {
                log.warn("==> Currently gateway does not have dynamic routing configurations");
            }
            log.info("==> End the gateway dynamic route initialization");

        } catch (Exception e) {
            log.error("==> An error occurred while initializing the gateway route: ", e);
        }
    }

}


